Променливи extern
Ключовата дума extern
предлага един метод за деклариране на променлива без да я дефинираме. По подобие
на прототипа на функция тя указва, че някъде в програмата е дефиниран
идентификатор от този тип.
extern int i;
дава “обещание”, че
някъде в програмата съществува дефиниция от вида
int
i;
Декларацията extern не предизвиква отделяне на памет. Тя може да бъде
писана многократно в програмата. Обикновено, обаче, тя се записва еднократно в
публичен заглавен файл за да бъде включвана, когато е
необходимо.
Ключовата дума extern може да бъде записвана и в прототип на
функция. Единственият ефект на това ще бъде, че неявната й характеристика
“дефинирана другаде” ще стане явна за прототипа. Това се прави по следния
начин
extern void putValues( int* , int );
Декларацията на
променлива extern в явен инициализатор се разглежда като дефиниция на тази
променлива. Отделя се памет и всяка следваща дефиниция на тази променлива в
същия обхват се отбелязва като грешна. Например,
extern conts bufSize =
512; // definition
Глобални променливи static
Глобална променлива,
която е предшествана от ключовата дума static ще бъде невидима вън от файла, в
който е дефинирана. Тези променливи и функции, които се отнасят само за файла, в
който са дефинирани, се декларират като static. По този начин те не могат да
влязат в конфликт с глобалните идентификатори в други файлове, в които случайно
се използват същите имена.
За идентификаторите static, които имат файлов
обхват, се казва, че притежават вътрешно свързване. (За глобалните
идентификатори, които не са static се казва, че притежават вътрешно свързване).
По подразбиране, дефинициите на функции inline и константи са static.
Ето
един пример за това кога една функция може да бъде декларирана като static. Тя
съдържа три функции
bsort(), qsort() и swap().
Предназначението на
bsort() и qsort() е да сортират масив във възходящ ред. Функцията swap() се вика
и от двете функции, но не са предназначени за обща употреба. За нашия пример те
са декларирани като static. (Друга алтернатива е да бъдат декларирани като
inline).
static void swap ( int *ia, int i, int j ) {
// swap two
elements of array
int
tmp = ia[ i ];
ia[ i ] = ia[ j ];
ia[ j ] =
tmp;
}
void bsort( int *ia, int sz ) {
// bubble sort
for ( int
i = 0; i < sz; i++ )
for ( int j = i++; j < sz; j++ )
if ( ia[ i ]
> ia[ j ] ) swap( ia, i, j );
}
void qsort( int *ia, int low, int
high ) {
// stopping condition for recursion
if ( low < high ){
int lo = low;
int hi = high + 1;
int elem = ia[ low ];
for (;;)
{ while ( ia[ ++lo ] <= elem );
while ( ia[ --hi ] > elem );
if ( lo
< hi )
swap( ia, lo, hi );
else break;
} //
end,
for(;;)
swap( ia, low, hi - 1 );
qsort( ia, low, hi - 1
);
qsort( ia, hi + 1, high );
} // endq if ( low < high
);
}
qsort() е една реализация на алгоритъма за бързо сортиране на
C.A.R Hoare. Нека разгледаме подробно тази функция. low и high задават долната и
горната граница на масива. qsort() е една рекурсивна функция, която прилага към
себе си прогресивно намаляващи под масиви. Условието за приключване на работа е
когато долната граница е равна (или по-голяма) от горната граница (ред
3).
elem (ред 6) се нарича разделящ елемент. Всички елементи на масива,
които са по-малки от elem се преместват от лявата му страна; а всички по-големи
елементи - отдясно. Сега масивът е разделен на два подмасива. qsort() се прилага
рекурсивно към всеки от тях (редове 18 - 19).
Предназначението на цикъла
for(;;) е да извърши разпределянето на елементите (редове 8 - 15). При всяка
итерация на цикъла lo се увеличава, докато не достигне индекса на първия елемент
на ia, който е по-голям от elem (ред 9). Съответно hi се намалява, докато не
достигне най-крайния индекс на елемент, който е по-малък или равен на elem (ред
10). Ако lo вече не е по-малко от hi елементите са били разпределени и ние
прекъсваме изпълнението на цикъла; иначе елементите се разменят и започва
следващата итерация (редове 12 - 14).
Въпреки, че масивът е бил
разпределен, elem все още се намира в ia[low]. Функцията swap() от ред 17 го
поставя на окончателната му позиция в масива. qsort() се прилага тогава към
двата подмасива.
Следната реализация на main(), която изпълнява двете
сортиращи функции, използува putValues() при отпечатването на
масива.
#include <stream.h>
#include "sort.h" /* bsort(),
qsort() */
#include "print.h" /* putValues() */
// for illustration,
predefine arrays
int ia1 [ 10 ] = { 26, 5, 37, 1, 61, 11, 59, 15, 48, 19 }
;
int ia2 [ 16 ] = { 503, 87, 512, 61, 908, 170, 897, 275, 653,
426, 154,
509, 612, 677, 765, 703 } ;
main() {
cout << "nBubblesort of
first array";
bsort( ia1, 10 );
putValues( ia1, 10 );
cout <<
"nQuicksort of second array";
qsort( ia2, 0, 15 );
putValues( ia2, 16
);
}
Когато компилираме и изпълним тази програма ще получим следния
резултат
Bubblesort of first array ( 10 )
< 1, 5, 11, 15, 19, 26,
37, 48, 59, 61 >
Quicksort of second array( 16 )
< 61, 87, 154,
170, 275, 426, 503, 509, 512, 612, 653, 677, 703, 897, 908
>